/**
 * 编码修复工具
 * 用于修复FBX/GLTF模型中的中文乱码问题
 */

/**
 * 修复字符串编码（处理中文乱码）
 * @param {string} str - 可能包含乱码的字符串
 * @returns {string} - 修复后的字符串
 */
export function fixStringEncoding(str) {
    if (!str || typeof str !== 'string') return str;
    
    try {
        // 检测多种乱码模式
        const garbledPatterns = [
            /[\u00C0-\u00FF]{2,}/,           // 连续latin1扩展字符
            /[çµå¨é¸�]/,                     // 特定乱码字符
            /Ã[^A-Za-z\s]/,                   // Ã 后跟非字母
            /[Ã¥Ã¦Ã¯Ã§Ã¨Ã©]/,              // 常见中文乱码
            /\uFFFD/,                         // 替换字符 � (U+FFFD) - 编码错误标志
        ];
        
        const hasGarbled = garbledPatterns.some(pattern => pattern.test(str));
        
        if (hasGarbled) {
            // 方法1: 从Latin1/ISO-8859-1转UTF-8
            try {
                const bytes = new Uint8Array(str.length);
                for (let i = 0; i < str.length; i++) {
                    bytes[i] = str.charCodeAt(i) & 0xff;
                }
                
                const fixed = new TextDecoder('utf-8', { fatal: false }).decode(bytes);
                
                // 验证修复后包含中文字符且不包含替换字符，且长度合理
                if (/[\u4e00-\u9fa5]/.test(fixed) && 
                    !/\uFFFD/.test(fixed) && 
                    fixed.length > 0 &&
                    fixed !== str) {
                    return fixed;
                }
            } catch (e) {
                console.warn('⚠️ 方法1失败:', e);
            }
            
            // 方法2: 尝试从UTF-8字节序列恢复（处理部分损坏的情况）
            try {
                const bytes = [];
                for (let i = 0; i < str.length; i++) {
                    const code = str.charCodeAt(i);
                    // 如果遇到 FFFD，尝试从前后文推断
                    if (code === 0xFFFD) {
                        // 跳过替换字符
                        continue;
                    }
                    bytes.push(code & 0xff);
                }
                
                if (bytes.length > 0 && bytes.length < str.length) {
                    // 有字符被跳过，尝试重新解码
                    const uint8Array = new Uint8Array(bytes);
                    const fixed = new TextDecoder('utf-8', { fatal: false }).decode(uint8Array);
                    
                    if (/[\u4e00-\u9fa5]/.test(fixed) && !/\uFFFD/.test(fixed)) {
                        return fixed;
                    }
                }
            } catch (e) {
                console.warn('⚠️ 方法2失败:', e);
            }
            
            // 方法3: 智能推断 - 基于常见词汇模式
            try {
                // 常见的材质名称词汇映射（使用数组而不是对象）
                const commonReplacements = [
                    // 摄�D头 -> 摄像头
                    { pattern: /摄[\uFFFD\x00-\x7F]{1,2}头/g, replacement: '摄像头' },
                    // 金�T白色 -> 金属白色
                    { pattern: /金[\uFFFD\x00-\x7F]{1,2}白/g, replacement: '金属白' },
                    // 其他常见模式...
                ];
                
                let fixed = str;
                let matched = false;
                
                for (const item of commonReplacements) {
                    if (item.pattern.test(fixed)) {
                        fixed = fixed.replace(item.pattern, item.replacement);
                        matched = true;
                        break;
                    }
                }
                
                if (matched) {
                    return fixed;
                }
                
                // 如果没有匹配到已知模式，尝试智能清理
                let cleaned = str;
                
                // 移除 � 和紧跟的异常字符
                cleaned = cleaned.replace(/\uFFFD[A-Za-z0-9]{0,2}/g, '');
                
                if (cleaned !== str && cleaned) {
                    if (/[\u4e00-\u9fa5a-zA-Z0-9]/.test(cleaned)) {
                        return cleaned;
                    }
                }
            } catch (e) {
                console.warn('⚠️ 方法3失败:', e);
            }
            
            // 如果所有方法都失败，保留原字符串但给出警告
            console.warn(`⚠️  无法完全修复编码，保留原字符串: "${str}"`);
        }
        
        return str;
    } catch (error) {
        console.warn('⚠️ 编码修复异常:', error.message);
        return str;
    }
}

/**
 * 修复Three.js模型对象中所有对象和材质的名称编码
 * 在FBX/GLTF加载完成后立即调用
 * @param {THREE.Object3D} object3D - Three.js 3D对象
 */
export function fixModelEncoding(object3D) {
    if (!object3D) return;
    
    let fixedCount = 0;
    let totalChecked = 0;
    
    object3D.traverse((child) => {
        // 修复对象名称
        if (child.name) {
            totalChecked++;
            const fixedName = fixStringEncoding(child.name);
            if (fixedName !== child.name) {
                child.name = fixedName;
                fixedCount++;
            }
        }
        
        // 修复材质名称
        if (child.material) {
            if (Array.isArray(child.material)) {
                // 多材质
                child.material.forEach(mat => {
                    if (mat && mat.name) {
                        totalChecked++;
                        const fixedName = fixStringEncoding(mat.name);
                        if (fixedName !== mat.name) {
                            mat.name = fixedName;
                            fixedCount++;
                        }
                    }
                });
            } else if (child.material.name) {
                // 单材质
                totalChecked++;
                const fixedName = fixStringEncoding(child.material.name);
                if (fixedName !== child.material.name) {
                    child.material.name = fixedName;
                    fixedCount++;
                }
            }
        }
    });
}

/**
 * 递归修复对象中所有字符串的编码
 * @param {*} obj - 要修复的对象
 * @returns {*} - 修复后的对象
 */
export function fixObjectEncoding(obj) {
    if (typeof obj === 'string') {
        return fixStringEncoding(obj);
    }
    
    if (Array.isArray(obj)) {
        return obj.map(item => fixObjectEncoding(item));
    }
    
    if (obj && typeof obj === 'object') {
        const fixed = {};
        for (const key in obj) {
            if (obj.hasOwnProperty(key)) {
                fixed[key] = fixObjectEncoding(obj[key]);
            }
        }
        return fixed;
    }
    
    return obj;
}

